package com.innodata.riskEngine.mock;

/**
 * @Author liboshuai
 * @Date 2023/11/2 19:18
 */

import com.innodata.riskEngine.common.pojo.ChannelDataPO;
import com.innodata.riskEngine.common.pojo.SourcePO;
import com.innodata.riskEngine.common.utils.json.JsonUtil;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;

@Slf4j
public class DataGenerator {

    /**
     * 银行可选集合
     */
    static final List<String> bankList = Arrays.asList("6100", "0560", "0541");
    /**
     * 渠道可选集合
     */
    static final List<String> channelList = Arrays.asList("game", "huajifen", "mall");

    /**
     * 用户id可选集合
     */
    static List<Long> lotteryNumberList = Arrays.asList(null, 0L, 1L, 2L);

    /**
     * 生成SourcePO对象数据
     *
     * @param bankSize          银行种类数量: 最小为1时，bank=6100。最大为3，分别为6100、0560、0541
     * @param channelSize       渠道种类数量：最小为1时，channel=game。最大为3，分别为game、huajifen、mall
     * @param userSize          用户种类数量：最小为1时，userId=userId-1。最多为int上限，userId后缀累加到数字
     * @param lotteryNumberSize 抽奖数量种类数量：最小为1时，lotteryNumber=1L。最多为4，分别为null、0、1、2
     * @return sourcePO 对象
     */
    public static SourcePO generateSourcePOList(int bankSize, int channelSize, int userSize, int lotteryNumberSize, long eventTimestamp) {
        // 非法参数效验
        illegalArgumentValidation(bankSize, channelSize, userSize, lotteryNumberSize);

        // 获取动态字段值Map
        Map<String, Object> dynamicFieldValueMap = getDynamicFieldValues(bankSize, channelSize, userSize, lotteryNumberSize);

        SourcePO sourcePO = new SourcePO();
        ChannelDataPO channelDataPO = new ChannelDataPO();
        String userId = (String) dynamicFieldValueMap.get("userId");
        channelDataPO.setUserId(userId);
        channelDataPO.setCampaignId("campaignId-" + Integer.parseInt(userId.split("-")[1]) / 100);
        channelDataPO.setLotteryNumber((Long) dynamicFieldValueMap.get("lotteryNumber"));
        sourcePO.setBank((String) dynamicFieldValueMap.get("bank"));
        sourcePO.setChannel((String) dynamicFieldValueMap.get("channel"));
        sourcePO.setEventTimestamp(eventTimestamp); // 设置 eventTimestamp
        sourcePO.setChannelData(channelDataPO);
        return sourcePO;
    }

    /**
     * 生成指定数量的SourcePO对象，并将它们写入到一个名为"source.json"的文件中。
     * 如果文件已存在，先清空文件，然后再写入新的数据。
     * 如果文件不存在，自动创建文件。
     *
     * @param numTasksPerSecond 每秒要生成的任务数量。乘以 totalRunTimeSeconds 等于总任务数。
     * @param totalRunTimeSeconds 总运行时间（秒）。即生成数据的总持续时间。
     * @param bankSize 银行种类数量。最小为1时，bank=6100。最大为3，分别为6100、0560、0541。
     * @param channelSize 渠道种类数量。最小为1时，channel=game。最大为3，分别为game、huajifen、mall。
     * @param userSize 用户种类数量。最小为1时，userId=userId-1。最多为int上限，userId后缀累加到数字。
     * @param lotteryNumberSize 抽奖数量种类数量。最小为1时，lotteryNumber=1L。最多为4，分别为null、0、1、2。
     */
    public static void generateSourcePOListToFile(long numTasksPerSecond, long totalRunTimeSeconds, int bankSize, int channelSize, int userSize, int lotteryNumberSize) {
        String filename = System.getProperty("user.home") + File.separator + "source.json";

        try {
            new FileWriter(filename, false).close();
        } catch (IOException e) {
            log.error("Error clearing file", e);
        }

        long eventTimestamp = System.currentTimeMillis();

        try (PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(filename, true)))) {
            for (long i = 0; i < totalRunTimeSeconds; i++) {
                // 计算这一批数据的基准 eventTimestamp，它比上一批数据的基准 eventTimestamp 大 1 秒
                eventTimestamp += TimeUnit.SECONDS.toMillis(1);

                for (long j = 0; j < numTasksPerSecond; j++) {

                    SourcePO sourcePO = generateSourcePOList(bankSize, channelSize, userSize, lotteryNumberSize, eventTimestamp);
                    writer.println(JsonUtil.obj2JsonStr(sourcePO));
                }
            }
        } catch (IOException e) {
            log.error("Error writing data to file", e);
        }
    }

    /**
     * 获取动态字段值
     */
    private static Map<String, Object> getDynamicFieldValues(int bankSize, int channelSize, int userSize, int lotteryNumberSize) {
        String bank;
        String channel;
        String userId;
        Long lotteryNumber;
        if (bankSize == 1) {
            bank = "6100";
        } else {
            bank = bankList.get(new Random().nextInt(bankSize));
        }
        if (channelSize == 1) {
            channel = "game";
        } else {
            channel = channelList.get(new Random().nextInt(channelSize));
        }
        if (userSize == 1) {
            userId = "userId-0";
        } else {
            userId = "userId-" + new Random().nextInt(userSize);
        }
        if (lotteryNumberSize == 1) {
            lotteryNumber = 1L;
        } else {
            lotteryNumber = lotteryNumberList.get(new Random().nextInt(lotteryNumberSize));
        }
        Map<String, Object> map = new HashMap<>();
        map.put("bank", bank);
        map.put("channel", channel);
        map.put("userId", userId);
        map.put("lotteryNumber", lotteryNumber);
        return map;
    }

    /**
     * 非法参数效验
     */
    private static void illegalArgumentValidation(int bankSize, int channelSize, int userSize, int lotteryNumberSize) {
        if (bankSize < 1 || bankSize > 3) {
            throw new IllegalArgumentException("bankSize 必须大于等于1，或者小于等于3");
        }
        if (channelSize < 1 || channelSize > 3) {
            throw new IllegalArgumentException("channelSize 必须大于等于1，或者小于等于3");
        }
        if (userSize < 1) {
            throw new IllegalArgumentException("userSize 必须大于等于1");
        }
        if (lotteryNumberSize < 1 || lotteryNumberSize > 4) {
            throw new IllegalArgumentException("lotteryNumberSize 必须大于等于1，或者小于等于4");
        }
    }
}